#include <stdlib.h>
#include <assert.h>
#include "plist.h"

typedef struct plist_node_s *plist_node_t;
struct plist_node_s{
	void *elem;
	plist_node_t next;
};
struct plist_s{
	plist_node_t front;
	plist_node_t back;
	plist_node_t next;
	plist_node_t prevback;
};

plist_t plist_create(void){
	plist_t list;

	list = malloc(sizeof(struct plist_s));
	if(list != NULL){
		list->front = NULL;
		list->back = NULL;
		list->next = NULL;
		list->prevback = NULL;
	}
	return list;
}

int plist_destroy(plist_t *list){
	void *elem;

	assert(list != NULL && *list != NULL);

	/* Vaciar si no esta vacía */
	while(!plist_is_empty(*list)){
		elem = plist_pop(*list);
		free(elem);
	}
	free(*list);
	*list = NULL;

	return 0;
}

bool plist_push(plist_t list, void *elem){
	plist_node_t node;

	assert(list != NULL);

	node = malloc(sizeof(struct plist_node_s));
	if(node != NULL){
		node->elem = elem;
		node->next = NULL;
		if(list->front == NULL){
			list->front = node;
			list->back = node;
		}
		else{
			node->next = list->front;
			list->front = node;
		}
		plist_rewind(list);
	}
	return true;
}

void* plist_pop(plist_t list){
	void *elem;
	plist_node_t node;

	assert(list != NULL && list->front != NULL);

	node = list->front;
	list->front = node->next;
	elem = node->elem;
	if(node == list->prevback) list->prevback = NULL;
	if(node == list->back) list->back = NULL;
	free(node);

	plist_rewind(list);
	return elem;
}

bool plist_append(plist_t list, void *elem){
	plist_node_t node;

	assert(list != NULL);

	node = malloc(sizeof(struct plist_node_s));
	if(node != NULL){
		node->elem = elem;
		node->next = NULL;
		if(list->front == NULL) list->front = node;
		else list->back->next = node;
		list->prevback = list->back;
		list->back = node;
		plist_rewind(list);
	}
	return true;
}

void* plist_remove_last(plist_t list){
	plist_node_t node;
    plist_node_t aux;

	void *elem;
    

	assert(list != NULL);

	if(list->prevback){
		node = list->back;
		list->back = list->prevback;
		elem = node->elem;
		free(node);
	}

	else if(list->front == list->back){
		node = list->back;
        list->back = NULL;
		list->front = NULL;
		elem = node->elem;
		free(node);
	}
	else elem = NULL;

    aux = list->front;
    while (aux != list->back){
        list->prevback = aux;
        aux = aux->next;
    }
	return elem;
}

void* plist_get_last(plist_t list){

	assert(list != NULL);
    return list->back->elem;

}

bool plist_is_empty(plist_t list){
	assert(list != NULL);

	return (list->front == NULL);
}

void plist_rewind(plist_t list){
	assert(list != NULL);

	list->next = list->front;
}

void* plist_get_next(plist_t list){
	void *elem;

	assert(list != NULL);
    
	if(list->next == NULL) elem = NULL;
	else{
		elem = list->next->elem;
		list->next = list->next->next;
	}

	return elem;
}

